#include <iostream>
using std::cout;
using std::endl;

class Point
{
public:
    static Point * getInstance(){
        if(nullptr == _pInstance){
            _pInstance = new Point(1,2);
        }
        return _pInstance;
    }

    void init(int x,int y){
        _ix = x;
        _iy = y;
    }

    void print(){
        cout << "(" << this->_ix
            << "," << this->_iy
            << ")" << endl;
    }

    static void destroy(){
        if(_pInstance){
            cout << ">> delete heap" << endl;
            delete _pInstance;
            _pInstance = nullptr;
        }

    }

private:
    Point() = default;

    Point(int x ,int y)
    : _ix(x)
    , _iy(y)
    {
        cout << "Point(int,int)" << endl;
    }
    
    //一般，析构函数的访问权限与构造函数相同，或者更严格
    ~Point(){
        cout << "~Point()" << endl;
    }

    //C++11提供的写法
    Point(const Point & rhs) = delete;
    Point & operator=(const Point & rhs) = delete;
private:
    int _ix;
    int _iy;
    static Point * _pInstance;
};
Point * Point::_pInstance = nullptr;

void test0(){
    /* Point * pt1 = Point::getInstance(); */
    /* Point * pt2 = Point::getInstance(); */
    /* cout << pt1 << endl; */
    /* cout << pt2 << endl; */
    /* delete pt1; */
    /* delete pt2; */
}

void test1(){
    //单例对象的规范使用
    //避免多个指针拥有单例对象的管理权
    Point::getInstance()->print();
    //把数据成员的初始化和赋值分开
    Point::getInstance()->init(19,78);
    Point::getInstance()->print();
    Point::getInstance()->init(76,28);
    Point::getInstance()->print();
    Point::destroy();
    //执行多次destroy函数
    //也不会发生double free问题
    Point::destroy();
    Point::destroy();
    Point::getInstance()->print();
    Point::destroy();

    //getInstance的返回值实际上是一个
    //由_pInstance复制而来的右值属性的指针变量
    //生命周期只有一行，
    //可以在本行调用Point的成员函数
    //但是不能对这个指针变量本身（getInstance的返回值）取地址
    /* &(Point::getInstance()); */

    //这种情况，销毁单例对象之后
    //如果多次调用destroy,实际上每次是又创建一个单例对象，
    //并马上销毁，不合理
    /* Point::getInstance()->destroy(); */
    /* Point::getInstance()->destroy(); */
}

int main(void){
    test1();
    return 0;
}
